package ponteiro;

import java.lang.reflect.*;

import net.sourceforge.sizeof.*;
import sun.misc.*;

public class MemoriaReal implements Memoria {

	public static final String TIPO = "real";
	private static Unsafe unsafe = getUnsafe();

	private static Unsafe getUnsafe() {
		Unsafe unsafe = null;
		try {
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			unsafe = (Unsafe) field.get(Unsafe.class);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return unsafe;
	}

	private static class Auxiliar {
		Object obj;
	}

	@SuppressWarnings("deprecation")
	@Override
	public long getEndereco(Object obj) {
		Auxiliar aux = getAux(obj);
		long fieldOffset = getFieldOffset(aux, "obj");
		long endereco = unsafe.getLong(aux, fieldOffset);
		if (obj.getClass().isArray()) {
			int arrayBaseOffset = unsafe.arrayBaseOffset(obj.getClass());
			endereco = unsafe.getInt(obj, arrayBaseOffset);
		}
		return endereco;
	}

	private Auxiliar getAux(Object obj) {
		Auxiliar aux = new Auxiliar();
		aux.obj = obj;
		return aux;
	}

	@Override
	public Object getObject(long endereco) {
		Auxiliar aux = getAux(null);
		long fieldOffset = getFieldOffset(aux, "obj");
		unsafe.putLong(aux, fieldOffset, endereco);
		return aux.obj;
	}

	@SuppressWarnings("deprecation")
	private static long getFieldOffset(Object obj, String field) {
		try {
			return unsafe.fieldOffset(obj.getClass().getDeclaredField(field));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public long adiciona(long endereco, long posicoes) {
		Object obj = getObject(endereco);
		long size = SizeOf.sizeOf(obj);
		return endereco + size;
	}

}
